#include "threadpool.h"
#include "runnable.h"
#include "thread.h"
#include "event.h"
#include <stdio.h>
#include <time.h>

using namespace std;

/// 伪线程，if no error occured or manually stoped, it will never stop
class PooledThread: public Runnable
{
public:
    PooledThread(const string& name, int stackSize = DEFAULT_STACK_SIZE);
    ~PooledThread();

    bool start(Runnable& target);
    bool idle();
    void join();
    void stop();
    int idleTime();
    virtual void run();
private:
    friend class ThreadPool;

private:

    time_t              m_idleTime;
    time_t              m_workTime;
    Runnable*           m_pTarget;
    string              m_name;
    Thread              m_thread;
    Event               m_targetReady;          /// auto reset
    bool                m_idle;
    /// 用于一个target运行结束后，再次运行另一个target，而不用重新新建线程
    bool                m_isReenterable;
};

PooledThread::PooledThread(const string& name, int stackSize): 
    m_pTarget(NULL), 
    m_name(name), 
    m_thread(name),
    m_targetReady(true),
    m_idle(true),
    m_isReenterable(false)
{
    m_thread.setStackSize(stackSize);
    time(&m_idleTime);
    m_thread.start(*this);
}

PooledThread::~PooledThread()
{
}

bool PooledThread::start(Runnable& target)
{
    if (m_isReenterable)
    {
        m_isReenterable = false;
    }
    if(!m_idle)
    {
        return false;
    }
    m_pTarget = &target;
    m_targetReady.set();

    return true;
}

inline bool PooledThread::idle()
{
    return m_idle && m_pTarget == NULL;
}

inline void PooledThread::join()
{
    m_thread.join();
}

int PooledThread::idleTime()
{
    if (m_idle)
    {
        return (int) (time(NULL) - m_idleTime);
    }

    return int(m_workTime - m_idleTime);
}

void PooledThread::stop()
{
    pthread_cancel(m_thread.id());
}

void PooledThread::run()
{
    for (;;)
    {
        m_targetReady.wait();   /// auto resetted
        pthread_testcancel();
        
        m_idle = false;
        if (m_pTarget)
        {
            m_workTime = time(NULL);
            m_pTarget->onStart();
            m_pTarget->run();
            m_pTarget->onFinished();
            m_pTarget  = NULL;
        }
        
        m_idleTime = time(NULL);
        m_isReenterable = true;
        m_idle = true;
    }
}

ThreadPool::ThreadPool(unsigned int minCapacity,
    unsigned int maxCapacity,
    int idleTime,
    unsigned int stackSize): 
    m_minCapacity(minCapacity), 
    m_maxCapacity(maxCapacity), 
    m_idleTime(idleTime),
    m_stackSize(stackSize)
{
    for (int i = 0; i < m_minCapacity; i++)
    {
        PooledThread* pThread = createThread();
        m_idleThreads.push_back(pThread);
    }
}

ThreadPool::ThreadPool(const string& name,
    unsigned int minCapacity,
    unsigned int maxCapacity,
    int idleTime,
    unsigned int stackSize):
    m_name(name),
    m_minCapacity(minCapacity), 
    m_maxCapacity(maxCapacity), 
    m_idleTime(idleTime),
    m_stackSize(stackSize)
{
    for (int i = 0; i < m_minCapacity; i++)
    {
        PooledThread* pThread = createThread();
        m_idleThreads.push_back(pThread);
    }
}

ThreadPool::~ThreadPool()
{
    stopAll();
    clearIdle();
}

void ThreadPool::addCapacity(int n)
{
    // n may be negative 
    ScopedMutex lock(&m_mutex);
    m_maxCapacity += n;
}

int ThreadPool::capacity()
{
    ScopedMutex lock(&m_mutex);
    return m_maxCapacity;
}

int ThreadPool::available()
{
    ScopedMutex lock(&m_mutex);
    
    adjustIdleWorking();
    
    return m_idleThreads.size();
}

int ThreadPool::working()
{
    ScopedMutex lock(&m_mutex);
    
    adjustIdleWorking();
    
    return m_workingThreads.size();
}

int ThreadPool::allocated()
{
    ScopedMutex lock(&m_mutex);
    return m_idleThreads.size() + m_workingThreads.size();
}

bool ThreadPool::start(Runnable& target)
{
    PooledThread* pThread = getThread();
    if (pThread != NULL)
        return pThread->start(target);

    return false;
}

void ThreadPool::stopAll()
{
    ScopedMutex lock(&m_mutex);
    for (ThreadList::iterator it = m_workingThreads.begin(); 
            it != m_workingThreads.end(); ++it)
    {
        (*it)->stop();
        delete *it;
    }
    m_workingThreads.clear();
}

void ThreadPool::joinAll()
{
    // 清理相关队列
    joinTimeoutWorkingThread(0);
}

void ThreadPool::clearIdle()
{
    ScopedMutex lock(&m_mutex);
    for (ThreadList::iterator it = m_idleThreads.begin(); it != m_idleThreads.end(); ++it)
    {
        delete *it;
    }
    m_idleThreads.clear();
}

void ThreadPool::joinTimeoutWorkingThread(unsigned int second)
{
    ScopedMutex lock(&m_mutex);
    /// 整理超时线程
    if (second > 0)
    {
        for(ThreadList::iterator it = m_workingThreads.begin();
                it != m_workingThreads.end();)
        {
            if ((*it)->m_workTime != 0 && time(NULL) - (*it)->m_workTime >= second)
            {
                (*it)->stop();
                delete *it;
                m_workingThreads.erase(it++);
                continue;
            }
            ++it;
        }
    }
    
    adjustIdleWorking();
}

void ThreadPool::adjustIdleWorking()
{
    /// 整理已运行完毕的线程
    for(ThreadList::iterator it = m_workingThreads.begin(); 
            it != m_workingThreads.end();)
    {
        if ((*it)->idle())
        {
            m_idleThreads.push_back(*it);
            m_workingThreads.erase(it++);
            continue;
        }
        it++;
    }
}

PooledThread* ThreadPool::getThread()
{
    ScopedMutex lock(&m_mutex);
    
    adjustIdleWorking();

    if (m_idleThreads.size() > 0)
    {
        PooledThread* pThread = m_idleThreads.front();
        m_idleThreads.pop_front();
        m_workingThreads.push_back(pThread);
        return pThread;
    }
    
    if (m_workingThreads.size() + m_idleThreads.size() < (unsigned int)m_maxCapacity)
    {
        PooledThread* pThread = createThread();
        m_workingThreads.push_back(pThread);
        return pThread;
    }

    return NULL;
}

PooledThread* ThreadPool::createThread()
{
    static int tid = 0;
    // getThread 已加锁
    char buf[256] = {0};
    snprintf(buf,255,"%s[#%d]",m_name.c_str(),++tid);
    tid = tid%100000;
    return new PooledThread(buf, m_stackSize);
}

ThreadPool& ThreadPool::defaultPool()
{
    static ThreadPool defaultpool("default",0);
    return defaultpool;
}




